package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.service.CartApiService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@SuppressWarnings("all")
public class CartApiServiceImpl implements CartApiService {

    @Autowired
    private ProductFeignClient productFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;



    /**
     * 加入购物车
     * @param skuId
     * @param skuNum
     * @param userId
     */
    @Override
    public void addToCart(Long skuId, Integer skuNum, String userId) {

        //获取缓存key,先根据传过来的这几个参数,生成一个key,用来存到缓存中,或者从缓存中获取数据
        String cartKey = getCartKey(userId);

        //根据key去redis中查询看看有没有缓存的数据
        /**
         *  redisTemplate.boundHashOps(cartKey):通过最外层的大key获取Value
         *  而value是多个类型相同的一对对map
         *  <String,String,CartInfo>:
         *  第一个是最外边的cartKey的类型
         *  第二个是value中map的key的类型
         *  第三个是value中map的value的类型
         */
        BoundHashOperations<String,String,CartInfo> boundHashOps = redisTemplate.boundHashOps(cartKey);

        CartInfo cartInfo=null;
        //判断boundHashOps中是否有skuId
        if(boundHashOps.hasKey(skuId.toString())){
            cartInfo = boundHashOps.get(skuId.toString());
            cartInfo.setSkuNum(cartInfo.getSkuNum()+skuNum);
            cartInfo.setIsChecked(1);
            cartInfo.setSkuPrice(productFeignClient.getSkuPrice(skuId));
            cartInfo.setUpdateTime(new Date());
        }else {
            cartInfo = new CartInfo();

            //根据前端传过来的skuId,远程调用product来获取商品信息,
            // 因为在CartInfo中需要的一些数据在skuInfo里面
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            if(skuInfo != null){
                //  给表的字段赋值！
                cartInfo.setUserId(userId);
                cartInfo.setSkuId(skuId);
                cartInfo.setCartPrice(skuInfo.getPrice());
                cartInfo.setSkuNum(skuNum);
                cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
                cartInfo.setSkuName(skuInfo.getSkuName());
                cartInfo.setCreateTime(new Date());
                cartInfo.setUpdateTime(new Date());
                cartInfo.setSkuPrice(skuInfo.getPrice());
            }
        }
        //把数据存到redis中去
        boundHashOps.put(skuId.toString(), cartInfo);
    }

    /**
     * 查询购物车列表
     * @param userId
     * @param userTempId
     * @return
     */
    @Override
    public List<CartInfo> getCartList(String userId, String userTempId) {
        /*
        1.判断是否登录,根据判断结果查询不同的购物车
        2.查询结果需要排序
        3.有可能需要合并
        在登录的情况下
                未登录-->登录合并
                合并完成之后,需要删除未登录购物车数据!
                case1:有userId,没有userTempId
                case2:没有userId,有userTempId  return noLoginCartInfoList----
                case3:有userId,有userTempId
                    登录后进行合并购物车
                   先判断未登录购物车集合有没有数据
                   有数据进行合并,并且将noLoginCartInfoList这个删除
                   没数据只需要登录购物车的数据
         */
        //  声明一个集合来存储未登录数据
        List<CartInfo> noLoginCartInfoList = null;

        if(!StringUtils.isEmpty(userTempId)){
            //这个说明是临时购物车
            //根据userId获取一下redis中最外层的key,用来获取redis中存储的购物车集合(结构看添加购物车方法)
            String cartnoKey = getCartKey(userTempId);
            BoundHashOperations<String,String,CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartnoKey);
            noLoginCartInfoList=boundHashOperations.values();
        }


        //先判断userId是否为空,空说明是未登录状态
        if(StringUtils.isEmpty(userId)){
            if(!CollectionUtils.isEmpty(noLoginCartInfoList)){
                noLoginCartInfoList.sort((o1,o2)->{
                    //按照更新时间排序
                    return DateUtil.truncatedCompareTo(o2.getUpdateTime(),o1.getUpdateTime(), Calendar.SECOND);
                });
            }
            //返回未登录数据
            return noLoginCartInfoList;
        }

        //如果上边都不满足,这个时候就说明是有临时购物车加登录后的购物车,需要整合操作
        //LoginCartInfoList:登录后的购物车数据   noLoginCartInfoList:临时购物车
        /**
         * 循环遍历未登录购物车集合
         *      在未登录购物车的skuId 与登录的购物车的skuId相对
         *          合并业务逻辑:skuNum +skuNum  更新时间
         *          更新价格
         *          选中状态合并
         *          修改缓存的数量
         *      else
         *          直接添加到缓存
         *       删除临时购物车
         *       获取到合并之后的排序结果
         *       返回结果
         *
         *
         *       if(!CollectionUtils.isEmpty(LoginCartInfoList)){
         *                 //这个里边说明没有临时id没有临时购物车,直接返回LoginCartInfoList这个即可
         *                 //把购物车里边的项进行排序后返回
         *                 LoginCartInfoList.sort((o1,o2)->{
         *                     return DateUtil.truncatedCompareTo(o1.getUpdateTime(),o2.getUpdateTime(),Calendar.SECOND);
         *                 });
         *             }
         *             //返回没有临时购物车登录后的购物车数据
         *             return LoginCartInfoList;
         */

        //获取登录后购物车的key
        String cartKey = getCartKey(userId);
        //定义一个属于登录的集合
        List<CartInfo> LoginCartInfoList = null;
        BoundHashOperations<String,String,CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        //如果临时购物车里边有购物项,这个时候需要进行整合
        if(!CollectionUtils.isEmpty(noLoginCartInfoList)){
            noLoginCartInfoList.stream().forEach(cartInfo -> {
                if(boundHashOperations.hasKey(cartInfo.getSkuId().toString())){
                    //合并业务逻辑:skuNum+skuNum  更新时间
                    CartInfo loginCartInfo = boundHashOperations.get(cartInfo.getSkuId().toString());
                    loginCartInfo.setSkuNum(loginCartInfo.getSkuNum()+cartInfo.getSkuNum());
                    //更新时间
                    loginCartInfo.setUpdateTime(new Date());
                    //最新价格
                    loginCartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));

                    //选中状态合并
                    if(cartInfo.getIsChecked().intValue()==1){
                        loginCartInfo.setIsChecked(1);
                    }
                    //修改缓存的数据
                    boundHashOperations.put(cartInfo.getSkuId().toString(),loginCartInfo);
                }else {
                    //直接添加到缓存
                    cartInfo.setUserId(userId);
                    cartInfo.setCreateTime(new Date());
                    cartInfo.setUpdateTime(new Date());
                    boundHashOperations.put(cartInfo.getSkuId().toString(),cartInfo);
                }
            });
            //删除临时购物车中的数据
            redisTemplate.delete(getCartKey(userTempId));
        }
        //获取到合并之后的数据
        LoginCartInfoList = redisTemplate.boundHashOps(cartKey).values();
        if(CollectionUtils.isEmpty(LoginCartInfoList)){
            return new ArrayList<>();
        }
        //设置合并之后的排序结果(个人不想排序,排序会改变位置,增加一条数据就会改一下位置)
        /*LoginCartInfoList.sort(((o1, o2) -> {
            return DateUtil.truncatedCompareTo(o2.getUpdateTime(),o1.getUpdateTime(), Calendar.SECOND);
        }));*/
        return LoginCartInfoList;
    }

    /**
     * 购物车勾选状态的修改
     * @param userId
     * @param skuId
     * @param isChecked
     */
    @Override
    public void checkCart(String userId, Long skuId, Integer isChecked) {
        //先获取大key
        String cartKey = this.getCartKey(userId);
        //根据cartKey获取整个购物车列表
        BoundHashOperations<String,String,CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        //根据skuId从整个购物车列表中获取所修改的购物项
        CartInfo cartInfo = boundHashOperations.get(skuId.toString());
        //判断
        if(cartInfo!=null){
            //修改isChecked的值
            cartInfo.setIsChecked(isChecked);
            //从新存到redis中去
            boundHashOperations.put(skuId.toString(),cartInfo);
        }
    }

    /**
     * 删除购物车项
     * @param userId
     * @param skuId
     */
    @Override
    public void deleteCart(String userId, Long skuId) {
        //获取大key
        String cartKey = this.getCartKey(userId);
        //获取整个购物车列表
        BoundHashOperations<String,String,CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        //根据skuId进行删除该购物车项
        if(skuId!=null){
            //这句话的意思是看看整个购物车列表中是否含有该key(商品)
            if(boundHashOperations.hasKey(skuId.toString())){
                boundHashOperations.delete(skuId.toString());
            }
        }
    }

    /**
     * 根据用户Id 查询购物车列表
     * @param userId
     * @return
     */
    @Override
    public List<CartInfo> getCartCheckedList(Long userId) {

        //获取大key
        String cartKey = this.getCartKey(userId.toString());
        BoundHashOperations<String,String,CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> cartInfos = boundHashOperations.values();
        //获取一个List用来封装数据返回
        //ArrayList<CartInfo> cartInfoList = new ArrayList<>();

        if(!CollectionUtils.isEmpty(cartInfos)){
            /*for (CartInfo cartInfo : cartInfos) {
                if(cartInfo.getIsChecked().intValue()==1){
                    //获取最新价格
                    cartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
                    //封装数据
                    cartInfoList.add(cartInfo);
                }
            }*/
            //上方的方法用stream的过滤方式来写
            List<CartInfo> cartInfoLists = cartInfos.stream().filter(cartInfo -> {
                //设置最新价格
                cartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
                return cartInfo.getIsChecked().intValue() == 1;
            }).collect(Collectors.toList());
            return cartInfoLists;
        }
        return new ArrayList<>();
    }


    /**
     * 获取缓存key
     * 先根据传过来的这几个参数,生成一个key,用来存到缓存中,或者从缓存中获取数据
     * @param userId
     * @return
     */
    private String getCartKey(String userId) {
        //定义key user:userId:cart
        return RedisConst.USER_KEY_PREFIX + userId
               + RedisConst.USER_CART_KEY_SUFFIX;
    }
}
